package com.kaishengit.dao.core;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Disjunction;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.transform.ResultTransformer;
import com.kaishengit.pojo.User;


@SuppressWarnings("unchecked")
public class BaseDao<T,PK extends Serializable> {

	
	private SessionFactory sessionFactory;
	private Class<?> clazz;
	
	
	public BaseDao() {
		Class<?> c = this.getClass();
		ParameterizedType pt = (ParameterizedType) c.getGenericSuperclass();
		Type[] types = pt.getActualTypeArguments();
		clazz = (Class<?>) types[0];
	}

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	public List<T> search(String q_pinyin, User user){
		Criteria c = getSession().createCriteria(clazz);
		c.add(Restrictions.or(Restrictions.like("name", q_pinyin,MatchMode.START), Restrictions.or(Restrictions.like("firstname",q_pinyin,MatchMode.START), Restrictions.like("pinyin",q_pinyin,MatchMode.START))));
		c.add(Restrictions.eq("user", user));
		return c.list();
	}

	public Page<T> findalldeal(String propertyName, Object user, String propertyName2, String progress,Page<T> page){
		Criteria c = getSession().createCriteria(clazz);
		Long totalCount = findCountByCriteria(c);
		page.setTotalCount(totalCount);
		c.setMaxResults(page.getPageSize());
		c.setFirstResult(page.getOffset());
		c.add(Restrictions.eq(propertyName,user));
		c.add(Restrictions.eq(propertyName2,progress));
		List<T> result = c.list();
		page.setResult(result);
		return page;
	}
	
	/**
	 * 根据属性值获得集合并根据page获得分页效果
	 * */
	
	public Page<T> findByPage(String propertyName, Object value,Page<T> page){
		Criteria c = getSession().createCriteria(clazz);
		Long totalCount = findCountByCriteria(c);
		page.setTotalCount(totalCount);
		c.setMaxResults(page.getPageSize());
		c.setFirstResult(page.getOffset());
		c.add(Restrictions.eq(propertyName,value));
		List<T> result = c.list();
		page.setResult(result);
		return page;
	}
	/**
	 * 根据两个属性值获得集合并根据page获得分页效果
	 * */
	
	public Page<T> findByTwoProperty(String propertyName1, Object value1,String propertyName2, Object value2,Page<T> page){
		Criteria c = getSession().createCriteria(clazz);
		Long totalCount = findCountByCriteria(c);
		page.setTotalCount(totalCount);
		c.setMaxResults(page.getPageSize());
		c.setFirstResult(page.getOffset());
		c.add(Restrictions.eq(propertyName1,value1));
		c.add(Restrictions.eq(propertyName2,value2));
		List<T> result = c.list();
		page.setResult(result);
		return page;
	}
	

	public List<T> findAllByProperty(String propertyName,Object value){
		Criteria c = getSession().createCriteria(clazz);
		c.add(Restrictions.eq(propertyName,value));
		return  c.list();
	}
	public List<T> findAllByProperty2(String propertyName,Object value){
		Criteria c = getSession().createCriteria(clazz);
		c.add(Restrictions.eq(propertyName,value));
		//c.addOrder(Order.asc("starttime"));
		c.addOrder(Order.asc("endtime"));
		
		return  c.list();
	}
	public List<T> findAllByProperty3(String propertyName,Object value){
		Criteria c = getSession().createCriteria(clazz);
		c.add(Restrictions.eq(propertyName,value));
		//c.addOrder(Order.asc("starttime"));
		c.addOrder(Order.asc("endtime"));
		
		return  c.list();
	}

	public Session getSession() {
		return sessionFactory.getCurrentSession();
	}

	public void save(T t) {
		getSession().saveOrUpdate(t);
	}
	public void del(PK id){
		T t=get(id);
		getSession().delete(t);
		
	}

	public T get(PK id) {
		return (T) getSession().get(clazz, id);
	}
	/**
	 * 删除某一个
	 * @return
	 */
	

	public List<T> findAll() {
		Criteria c = getSession().createCriteria(clazz);
		return c.list();
	}

	public List<T> findByPage(Integer start,Integer rows) {
		Criteria c = getSession().createCriteria(clazz);
		c.setFirstResult(start);
		c.setMaxResults(rows);
		return c.list();
	}
	
	public T findByUnique(String propertyName,Object value) {
		Criteria c = getSession().createCriteria(clazz);
		c.add(Restrictions.eq(propertyName, value));
		return (T) c.uniqueResult();
	}
	

	public List<T> findBy(String propertyName,String value) {
		Criteria c = getSession().createCriteria(clazz);
		c.add(Restrictions.eq(propertyName, value));
		return c.list();
	}

	public List<T> find(String hql,Object...args) {
		return createQuery(hql, args).list();
	}
	

	public List<T> find(String hql,Map<String,Object> map) {
		return createQuery(hql, map).list();
	}
	

	public T findUnique(String hql,Object...args) {
		return (T) createQuery(hql, args).uniqueResult();
	}
	

	public T findUnique(String hql,Map<String,Object> map) {
		return (T) createQuery(hql, map).uniqueResult();
	}
	

	public List<T> find(Criterion... criterions) {
		return createCriteria(criterions).list();
	}
	

	public T findUnique(Criterion... criterions) {
		return (T) createCriteria(criterions).uniqueResult();
	}
	

	public List<T> find(List<Where> wheres){
		return builderCriteriaByWhereList(wheres).list();
	}
	

	public Page<T> find(List<Where> wheres,Page<T> page){
		Criteria c = builderCriteriaByWhereList(wheres);

		Long totalcount = findCountByCriteria(c);
		page.setTotalCount(totalcount);
		
		c.setFirstResult(page.getOffset());
		c.setMaxResults(page.getPageSize());

		if(page.getOrder() != null && page.getOrderBy() != null) {
			String[] orders = page.getOrder().split(",");
			String[] orderBys = page.getOrderBy().split(",");
			
			if(orders != null && orderBys != null) {
				if(orders.length != orderBys.length) {
					throw new IllegalArgumentException("排序属性和排序方式数量不对应!");
				} else {
					for(int i = 0;i < orderBys.length;i++) {
						String orderBy = orderBys[i];
						if(orderBy.equalsIgnoreCase("asc")) {
							c.addOrder(Order.asc(orders[i]));
						} else if (orderBy.equalsIgnoreCase("desc")) {
							c.addOrder(Order.desc(orders[i]));
						} else {
							throw new IllegalArgumentException("排序方式必须是asc或desc");
						}
					}
				}
			}
		}
		
		List<T> result = c.list();
		page.setResult(result);
		return page;
	}
	

	private Long findCountByCriteria(Criteria c) {
		
		@SuppressWarnings("static-access")
		ResultTransformer t = c.ROOT_ENTITY;
		
		c.setProjection(Projections.rowCount());
		Long result =  (Long) c.uniqueResult();
		
		c.setProjection(null);
		c.setResultTransformer(t);
		
		return result != null ? result : 0;
	}



	public T findUnique(List<Where> wheres) {
		return (T) builderCriteriaByWhereList(wheres).uniqueResult();
	}
	

	private Criteria builderCriteriaByWhereList(List<Where> wheres) {
		Criteria c = getSession().createCriteria(clazz);
		for(Where where : wheres) {
			
			if(where.getProperty().contains("_OR_")) {
				Criterion criterion = builderORCriterionByWhere(where);
				c.add(criterion);
			} else {
				Criterion criterion = builderCriterionByWhere(where);
				if(criterion != null) {
					c.add(criterion);
				}
			}
		}
		return c;
	}

	private Criterion builderORCriterionByWhere(Where where) {
		String[] propertyNames = where.getProperty().split("_OR_");

		Disjunction disjunction = Restrictions.disjunction();
		for(String property : propertyNames) {
			Criterion criterion = builderCriterionByWhere(where.getMathType(), property, where.getValue());
			disjunction.add(criterion);
		}
		return disjunction;
	}


	private Criterion builderCriterionByWhere(Where where) {
		if(where != null) {
			String matchType = where.getMathType();
			String property = where.getProperty();
			String value = where.getValue();
			return builderCriterionByWhere(matchType, property, value);
		}
		return null;
	}


	public Criterion builderCriterionByWhere(String matchType, String property, String value) {
		if(MatchType.EQ.equalsIgnoreCase(matchType)) {
			return Restrictions.eq(property, value);
		} else if(MatchType.GE.equalsIgnoreCase(matchType)) {
			return Restrictions.ge(property, value);
		} else if(MatchType.GT.equalsIgnoreCase(matchType)) {
			return Restrictions.gt(property, value);
		} else if(MatchType.LE.equalsIgnoreCase(matchType)) {
			return Restrictions.le(property, value);
		} else if(MatchType.LT.equalsIgnoreCase(matchType)) {
			return Restrictions.lt(property, value);
		} else if(MatchType.LIKE.equalsIgnoreCase(matchType)) {
			return Restrictions.like(property, value, MatchMode.ANYWHERE);
		}
		return null;
	}


	public Criteria createCriteria(Criterion... criterions) {
		Criteria c = getSession().createCriteria(clazz);
		for(Criterion cri : criterions) {
			c.add(cri);
		}
		return c;
	}
	

	public Query createQuery(String hql,Object...args) {
		Query query = getSession().createQuery(hql);
		for (int i = 0; i < args.length; i++) {
			query.setParameter(i, args[i]);
		}
		return query;
	}

	public Query createQuery(String hql,Map<String,Object> map) {
		Query query = getSession().createQuery(hql);
		query.setProperties(map);
		return query;
	}
	
	
	
}
